function varargout = computeCodeMetrics(modelName, varargin)
% 函数功能：计算生成代码的度量指标
%   computeCodeMetrics 计算生成代码的度量指标，然后生成Bug Finder报告
%
%   语法：
%   computeCodeMetrics(ModelName)
%   computeCodeMetrics(ModelName, 'TreatAsTopMdl')
%
%   输入参数：
%   modelName - 要分析的Simulink模型名称
%   varargin - 可选参数，用于指定是否作为顶层模型处理
%
%   输出参数：
%   varargout - 可变输出参数，包含分析结果结构体
%
%   

% 检查Polyspace Bug Finder许可证是否可用
if ~license('test', 'Polyspace_BF')
    DAStudio.error('certqualkit:engine:PSBFMissLicense');
end

% 检查Polyspace Bug Finder或Bug Finder Server是否可用
if isempty(ver('psbugfinder')) && isempty(ver('psbugfinderserver'))
    error('Link to either Polyspace Bug Finder or Polyspace Bug Finder Server is not available. See "Integrate Polyspace with MATLAB and Simulink" for more information.');
end

% 关闭所有已打开的模型
bdclose('all');

% 获取有用的文件夹/文件路径和名称
psprjDir = ProjectPathManager.getDirPath('code metrics', modelName);  % 代码度量项目目录
resultDir = fullfile(psprjDir, modelName);                      % 结果目录
tmplDir = fullfile(polyspaceroot, 'toolbox', 'polyspace', 'psrptgen', 'templates', 'bug_finder');  % 模板目录

% 如果模型特定的文件夹不存在，则创建它
if ~exist(psprjDir, 'dir')
    mkdir(psprjDir);
end

% 检查模型启动脚本是否存在
if ~exist(ProjectNamingManager.getNameStr('load command', modelName), 'file')
    error(['Model startup script ''', ProjectNamingManager.getNameStr('load command', modelName), ''' not found.']);
end
% Bug Finder会自动检查生成的代码是否存在

% 打开Simulink模型
disp(['Opening Simulink model ', modelName, '.']);
evalin('base', ProjectNamingManager.getNameStr('load command', modelName));

% 对于computeCodeMetrics，始终使用DEV格式，因为此函数没有CI模式
reportFormat = getReportFormatConfig('code metrics', 'DEV');

% 为Bug Finder创建配置（仅代码度量）
disp(['Analyzing code of Simulink model ', modelName, '.']);
psCfg = pslinkoptions(modelName);                    % 获取Polyspace链接选项
psCfg.VerificationMode = 'BugFinder';               % 设置验证模式为BugFinder
psCfg.VerificationSettings = 'PrjConfig';           % 使用项目配置进行验证设置
psCfg.CxxVerificationSettings = 'PrjConfig';        % 使用项目配置进行C++验证设置
psCfg.EnableAdditionalFileList = false;             % 禁用附加文件列表
psCfg.AdditionalFileList = {};                      % 清空附加文件列表
psCfg.AutoStubLUT = true;                           % 自动存根查找表
psCfg.InputRangeMode = 'DesignMinMax';              % 输入范围模式：设计最小最大值
psCfg.ParamRangeMode = 'None';                      % 参数范围模式：无
psCfg.OutputRangeMode = 'None';                     % 输出范围模式：无
psCfg.ModelRefVerifDepth = 'Current model only';    % 模型引用验证深度：仅当前模型
psCfg.ModelRefByModelRefVerif = false;              % 禁用模型引用间的验证
psCfg.AddSuffixToResultDir = false;                 % 不为结果目录添加后缀
psCfg.AddToSimulinkProject = false;                 % 不添加到Simulink项目
psCfg.OpenProjectManager = false;                   % 不打开项目管理器
psCfg.CheckconfigBeforeAnalysis = 'OnWarn';         % 分析前检查配置：仅在警告时

% 根据输入参数决定是否作为顶层模型处理
if nargin > 1 && ~isempty(varargin{1})
    psprjCfg = polyspace.ModelLinkOptions(modelName, psCfg, false);  % 不作为顶层模型
    tempDir = ['results_', modelName];                               % 临时目录名称
else
    psprjCfg = polyspace.ModelLinkOptions(modelName, psCfg, true);   % 作为顶层模型
    tempDir = ['results_mr_', modelName];                            % 临时目录名称（模型引用）
end

% 根据目标语言标准设置编译器选项
if contains(get_param(modelName, 'TargetLangStandard'), 'C90')
    psprjCfg.TargetCompiler.NoLanguageExtensions = true;   % 如果为C90标准，则遵守C90标准
else
    psprjCfg.TargetCompiler.NoLanguageExtensions = false;  % 否则默认为C99标准
end

% 配置Bug Finder分析选项
psprjCfg.BugFinderAnalysis.EnableCheckers = false;         % 禁用检查器
psprjCfg.CodingRulesCodeMetrics.CodeMetrics = true;        % 启用代码度量
psprjCfg.CodingRulesCodeMetrics.EnableMisraC3 = false;     % 禁用MISRA C:2012
psprjCfg.CodingRulesCodeMetrics.Misra3AgcMode = false;     % 禁用MISRA C:2012 AGC模式
psprjCfg.CodingRulesCodeMetrics.BooleanTypes = {'boolean_T'};  % 设置布尔类型
psprjCfg.Macros.DefinedMacros = {'main=main_rtwec', '__restrict__='};  % 定义宏

% 注释掉的配置选项（保留供参考）
% psprjCfg.InputsStubbing.GenerateResultsFor = 'all-headers';
% psprjCfg.Advanced.Additional = '-stub-embedded-coder-lookup-table-functions';

% 设置结果目录并生成项目配置文件
psprjCfg.ResultsDir = resultDir;  % 设置结果目录
psprjCfg.generateProject(fullfile(psprjDir, [modelName, '_CodeMetricsOnly_config.psprj']));  % 生成项目配置文件

% 使用Bug Finder配置中启用的度量指标来测量生成的代码
psprj = polyspace.Project();      % 创建Polyspace项目对象
psprj.Configuration = psprjCfg;   % 设置项目配置
psprj.run('bugFinder');           % 运行Bug Finder分析

% 生成代码度量报告
tmplFile = fullfile(tmplDir, 'CodeMetrics.rpt');  % 模板文件路径
rptFile = fullfile(psprjDir, [ProjectNamingManager.getNameStr('code metrics report', modelName), '.', lower(reportFormat)]);  % 报告文件路径
% 使用polyspace_report生成报告
polyspace_report('-template', tmplFile, '-format', upper(reportFormat), '-output-name', rptFile, '-results-dir', resultDir, '-noview');
% 如果报告文件存在，则打开它
if exist(rptFile, 'file')
    open(rptFile);
end

% 删除临时结果文件夹
if exist(tempDir, 'dir')
    rmdir(tempDir, 's');  % 删除临时目录及其内容
end

% 关闭Simulink模型
disp(['Closing Simulink model ', modelName, '.']);
close_system(modelName, 0);

% 设置成功消息
result.Message = ['Code metrics report for ', modelName, ' is successfully generated.'];
% 如果有输出参数，则设置返回值
if nargout > 0
    varargout{1} = result;
end
% 显示结果消息
disp(result.Message);

end
